package name.williamwall.buxoid;
/**
 * This software is made available under the Gnu General Public License v3
 * and has absolutely no waranty. You may change the software to suit your needs.
 * 
 * Author: William Wall, IV
 */
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Calendar;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.TabActivity;
import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
import android.text.method.PasswordTransformationMethod;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TabHost;
import android.widget.TabWidget;

public class Buxoid extends TabActivity {
	private String mTag;
	protected static long mViewAccountId;
	protected static int mMonth, mYear, mMaxMonth, mMaxYear;
	protected static String mViewTag;
	protected static String mUser, mPass;
	private static Dialog mWin;
	private static EditText mPassBox;
	protected static BuxoidDb mDb;
	protected static Handler mUICallback;
	protected static Runnable mFinish;
	
	@Override
    protected void onCreate(Bundle savedInstanceState) {
//		Log.d("Buxfer", "created Buxoid with state " + (savedInstanceState == null ? "null": "set"));
		
        super.onCreate(savedInstanceState);
        
        final TabHost tabHost = getTabHost();

        tabHost.addTab(tabHost.newTabSpec("accounts")
                .setIndicator("", this.getResources().getDrawable(R.drawable.accounts_on))
                .setContent(new Intent(this, AccountList.class)));

        tabHost.addTab(tabHost.newTabSpec("transactions")
                .setIndicator("", this.getResources().getDrawable(R.drawable.transactions_off))
                .setContent(new Intent(this, TransactionList.class)));
        
        tabHost.addTab(tabHost.newTabSpec("budgets")
                .setIndicator("", this.getResources().getDrawable(R.drawable.budgets_off))
                .setContent(new Intent(this, BudgetList.class)));
        
        tabHost.addTab(tabHost.newTabSpec("expenses")
                .setIndicator("", this.getResources().getDrawable(R.drawable.expenses_off))
                .setContent(new Intent(this, Analysis.class)));
        
        tabHost.addTab(tabHost.newTabSpec("impacts")
                .setIndicator("", this.getResources().getDrawable(R.drawable.impacts_off))
                .setContent(new Intent(this, ImpactList.class)));
        
        // if mTag is still null, try setting it from the extras in the intent
        if (mTag == null) {
        	Bundle extras = getIntent().getExtras();
        	mTag = extras != null ? extras.getString("tab"): null;
        }
        
        if (mTag != null) {
        	tabHost.setCurrentTabByTag(mTag);
        	if (!mTag.equals("accounts")) {
        		setOffIcon(tabHost.getTabWidget(), "accounts");
        		setOnIcon(tabHost.getTabWidget(), mTag);
        	}
        } else {
        	mTag = tabHost.getCurrentTabTag();
        }
        
        /**
         * Why is it so hard to change the tab icon?
         */
        tabHost.setOnTabChangedListener(new TabHost.OnTabChangeListener() {
			public void onTabChanged(String tabId) {
				setOffIcon(tabHost.getTabWidget(), mTag);
				mTag = tabId;
				setOnIcon(tabHost.getTabWidget(), mTag);
			}
        });
        
        // set initial month and year
        Calendar cal = Calendar.getInstance();
        mMonth = mMaxMonth = cal.get(Calendar.MONTH);
        mYear = mMaxYear = cal.get(Calendar.YEAR);
        
        // set initial transaction view to view all accounts
        mViewAccountId = 0;
        
    }

	@Override
	protected void onChildTitleChanged(Activity childActivity, CharSequence title) {
		setTitle(title);
	}
	
	@Override
	protected void onStart() {
	    super.onStart();
	    mDb = new BuxoidDb(this);
        mDb.open();
	}
	
	@Override
	protected void onStop() {
		super.onStop();
//		Log.d(getClass().getSimpleName(), "stopping Buxoid");
		mDb.close();
	}

	@Override
	protected void onRestoreInstanceState(Bundle state) {
//		Log.d("Buxfer", "Buxoid restore state");
		super.onRestoreInstanceState(state);
		mMonth = state.getInt("month");
		mMaxMonth = state.getInt("maxMonth");
		mYear = state.getInt("year");
		mMaxYear = state.getInt("maxYear");
		mViewAccountId = state.getLong("viewAccountId");
		mTag = state.getString("tag");
		mViewTag = state.getString("tagName");
		getTabHost().setCurrentTabByTag(mTag);
	}

	@Override
	protected void onSaveInstanceState(Bundle outState) {
//		Log.d("Buxfer", "saving Buxoid state");
		super.onSaveInstanceState(outState);
		outState.putInt("month", mMonth);
		outState.putInt("maxMonth", mMaxMonth);
		outState.putInt("year", mYear);
		outState.putInt("maxYear", mMaxYear);
		outState.putLong("viewAccountId", mViewAccountId);
		outState.putString("tag", mTag);
		outState.putString("tagName", mViewTag);
	}

	/**
	 * Changes the icon for the specified tabId to the off state
	 * @param tw the tab widget
	 * @param tabId the string id of the tab to change
	 */
	private void setOffIcon(TabWidget tw, String tabId) {
		int pos = 0;
		Drawable d = null;
		if (tabId.equals("accounts")) {
			pos = 0;
			d = this.getResources().getDrawable(R.drawable.accounts_off);
		} else if (tabId.equals("transactions")) {
			pos = 1;
			d = this.getResources().getDrawable(R.drawable.transactions_off);
		} else if (tabId.equals("budgets")) {
			pos = 2;
			d = this.getResources().getDrawable(R.drawable.budgets_off);
		} else if (tabId.equals("expenses")) {
			pos = 3;
			d = this.getResources().getDrawable(R.drawable.expenses_off);
		} else if (tabId.equals("impacts")) {
			pos = 4;
			d = this.getResources().getDrawable(R.drawable.impacts_off);
		}
		
		ImageView v = (ImageView) ((RelativeLayout) tw.getChildAt(pos)).getChildAt(0);
		v.setImageDrawable(d);
	}
	
	/**
	 * Changes the icon for the specified tab to the on state.
	 * @param tw the tab widget
	 * @param tabId the string id of the tab to change
	 */
	private void setOnIcon(TabWidget tw, String tabId) {
		int pos = 0;
		Drawable d = null;
		if (tabId.equals("accounts")) {
			pos = 0;
			d = this.getResources().getDrawable(R.drawable.accounts_on);
		} else if (tabId.equals("transactions")) {
			pos = 1;
			d = this.getResources().getDrawable(R.drawable.transactions_on);
		} else if (tabId.equals("budgets")) {
			pos = 2;
			d = this.getResources().getDrawable(R.drawable.budgets_on);
		} else if (tabId.equals("expenses")) {
			pos = 3;
			d = this.getResources().getDrawable(R.drawable.expenses_on);
		} else if (tabId.equals("impacts")) {
			pos = 4;
			d = this.getResources().getDrawable(R.drawable.impacts_on);
		}
		
		ImageView v = (ImageView) ((RelativeLayout) tw.getChildAt(pos)).getChildAt(0);
		v.setImageDrawable(d);
	}
	
	/**
	 * Decrements the global month variable (Buxoid.mMonth) to the previous month.
	 * The global month variable is an integer between 0 and 11. This function
	 * will decrement the year and reset the month variable if necessary. 
	 */
	public static void prevMonth() {
		mMonth--;
		if (mMonth == -1) {
			mYear--;
			mMonth = 11;
		}
	}
	
	/**
	 * Increments the global month variable (Buxoid.mMonth) to the next month.
	 * The global month variable is an integer between 0 and 11. This function
	 * will increment the year and reset the month if necessary.
	 */
	public static void nextMonth() {
		if (mYear == mMaxYear && mMonth < mMaxMonth) {
			mMonth++;
		} else if (mYear < mMaxYear){
			mMonth++;
			if (mMonth == 12) {
				mYear++;
				mMonth = 0;
			}
		}
	}
	
	/**
	 * Generates an MD5 hash from the given input
	 * @param input the string to hash
	 * @return an MD5 hash as a string
	 */
	public static String getMd5Hash(String input) {
		try {
			MessageDigest md = MessageDigest.getInstance("MD5");
			byte[] messageDigest = md.digest(input.getBytes());
			BigInteger number = new BigInteger(1, messageDigest);
			String md5 = number.toString(16);

			while (md5.length() < 32)
				md5 = "0" + md5;

			return md5;
		} catch (NoSuchAlgorithmException e) {
//			Log.e("MD5", e.getMessage());
			return null;
		}
	}
	
	/**
	 * Updates the program data from Buxfer.com. This method will prompt the
	 * user for their password if they chose not to save it.
	 * @param context The context in which to run
	 */
	public static void update(Context context) {
    	mUser = mDb.getSetting(BuxoidDb.SETTING_USER);
    	mPass = mDb.getSetting(BuxoidDb.SETTING_PASS);
    	
    	// if the user opted not to store the password, then prompt for it
    	if (mPass == null || mPass.length() == 0) {
    		promptPass(context);
    		// onClickListener for button in prompt calls updateData,
    		// so there is no need to call it here
    	} else {
    		updateData(context);
    	}
    }
    
    private static void updateData(Context context) {
        context.startService(new Intent(context, UpdateService.class));
    }
    
    public static void updateDone() {
        if (mUICallback != null && mFinish != null) {
            try {
                mUICallback.post(mFinish);
            } catch (Exception e) {
            }
            mUICallback = null;
            mFinish = null;
        }
    }
    
    /**
     * Prompts the user for their password
     * @param context the context in which to display the prompt
     */
    private static void promptPass(final Context context) {
		LinearLayout layout = new LinearLayout(context);
		layout.setOrientation(LinearLayout.VERTICAL);
		LinearLayout.LayoutParams p = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
		
		mPassBox = new EditText(context);
		mPassBox.setTransformationMethod(new PasswordTransformationMethod());
		mPassBox.setMaxLines(1);
		
		Button ok = new Button(context);
		ok.setText("OK");
		
		ok.setOnClickListener(new View.OnClickListener() {
			public void onClick(View view) {
			    // store password
			    mPass = mPassBox.getText().toString();
				mWin.dismiss();
				
				if (mPass.length() > 0) {
				    mDb.putSetting(BuxoidDb.SETTING_PASS, mPass);
					updateData(context);
				} else {
					AlertDialog.Builder adb = new AlertDialog.Builder(context);
					adb.setCancelable(true);
					adb.setMessage("No password given.");
					adb.setTitle("ERROR");
					adb.create().show();
				}
			}
		});
		
		int width = ((Activity) context).getWindowManager().getDefaultDisplay().getWidth() * 3 / 4;
		mPassBox.setWidth(width);
		
		layout.addView(mPassBox, p);
		layout.addView(ok, p);
		
		mWin = new Dialog(context);
		mWin.setTitle("Enter your password:");
		mWin.setContentView(layout);
		mWin.show();
	}
	
}
